local type,select,pairs,unpack,tostring=
	  type,select,pairs,unpack,tostring
module(..., package.seeall)

local dbutil = {}
local dbutil_mt = {__metatable = {}, __index = dbutil}

function MakeInhMT(ch)
	ch=ch or {}
	for _i,_j in pairs(dbutil) do
		ch[_i]=_j
	end
	return ch
end

function dbutil:onrestore()
	local base=self._base or self
	if base.con then base.con:close() end
	local con,msg = base.env:connect(unpack(base.params))
	base.con=con
	if not con then
		error("Could not connect to database " ..tostring(msg)..' '..tostring(base.params and base.params[1]))
	end
	base:init()
	local subs=base._sub
	if subs then
		for k,v in pairs(subs) do
			v:init()
		end
	end
end

-----------------------------------------------------------------------------
-- Executes a query using the MySQL connection.  This function is exposed to
-- allow other code to hook it if necessary, since we cannot hook con.execute
--
-- @param query          the query to be executed
-- @param noreconnect    do not attempt to reconnect to server if it has died
-----------------------------------------------------------------------------
function dbutil:execute(query, noreconnect)
	local cur, err
	if self.con then
		cur,err = self.con:execute(query)
	else
		err="gone away"
	end
	if cur then
	elseif cur == nil and err and err:match("gone away") and not noreconnect then
		-- Reopen the connection to the db server
		self:onrestore()
		cur,err=self.con:execute(query)
	end
	--print(query,cur,err)
	return cur, err
end

function dbutil:transdo(fn)
	local r,err,msg=xpcall(function()
		self.con:setautocommit(false)
		local r1,r2=fn()
		self.con:commit()
		return r1,r2
	end,debug.traceback)
	if not r then self.con:rollback() end
	self.con:setautocommit(true)
	if not r then error(err) end
	return err,msg
end

function dbutil:escape(value)
	return self.con:escape(value)
end

function dbutil:fmt_type(t)
	error('not impl')
end

function dbutil:prepare_val(value,ty)
	local ty = ty or type(value)

	if ty == 'string' then
		value = "'" .. self.con:escape(value) .. "'"
	elseif ty == 'nil' then
		value = 'null'
	else
		value = tostring(value)
	end
	return value
end
function dbutil:prepare(statement, ...)
	local count = select('#', ...)
	local escape=self.escape
	if count > 0 then
		local someBindings = {}

		for index = 1, count do
			local value = select(index, ...)
			local type = type(value)

			if type == 'string' then
				value = "'" .. escape(self,value) .. "'"
			elseif type == 'nil' then
				value = 'null'
			else
				value = tostring(value)
			end

			someBindings[index] = value
		end
		if not pcall(function() statement:format(unpack(someBindings)) end) then
			print('sss',...)
			print('12',statement)
			print(debug.traceback())
		end
		statement = statement:format(unpack(someBindings))
	end

	return statement
end
